package com.slipper.sfts.order.service;

import com.slipper.common.bo.Result;
import com.slipper.common.util.ResultUtil;
import com.slipper.common.util.StockUtil;
import com.slipper.common.util.StringUtil;
import com.slipper.common.util.Tool;
import com.slipper.qmt.constants.Constants;
import com.slipper.sfts.api.broker.bo.BrokerAccountBO;
import com.slipper.sfts.api.member.bo.MemberBrokerAccountBO;
import com.slipper.sfts.api.order.bo.OrderBO;
import com.slipper.sfts.api.stock.bo.StockOrderBO;
import com.slipper.sfts.api.stock.bo.StockPositionBO;
import com.slipper.sfts.broker.service.BrokerAccountService;
import com.slipper.sfts.member.service.MemberBrokerAccountService;
import com.slipper.sfts.stock.service.StockOrderService;
import com.slipper.qmt.QmtProxy;
import com.slipper.sfts.stock.service.StockPositionService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;

@Service
public class OrderService {
    @Resource
    private StockOrderService stockOrderService;
    @Resource
    private StockPositionService stockPositionService;
    @Resource
    private BrokerAccountService brokerAccountService;
    @Resource
    private MemberBrokerAccountService memberBrokerAccountService;
    @Resource
    private QmtProxy qmtProxy;

    public Result<OrderBO> order(OrderBO bo) {
        if (StringUtil.isBlank(bo.getMemberId())
                || StringUtil.isBlank(bo.getBrokerAccountId())
                || StringUtil.isBlank(bo.getOrderType())
                || StringUtil.isBlank(bo.getCode())
                || bo.getPrice() == null || bo.getPrice().compareTo(new BigDecimal(0)) <= 0
                || bo.getVolume() == null || bo.getVolume() <= 0) {
            return ResultUtil.failureResult("参数错误！");
        }
        // 卖出时判断持仓量是否足够
        if (StockOrderBO.ORDER_TYPE_SELL == bo.getOrderType()) {
            StockPositionBO position = stockPositionService.queryOneBy(
                    bo.getMemberId(), bo.getBrokerAccountId(), bo.getCode());
            if (position == null
                    || position.getAvailableVolume() == null
                    || position.getAvailableVolume() < bo.getVolume()) {
                return ResultUtil.failureResult("持仓量不足，无法下单！");
            }
        } else {
            // 买入时判断金额是否足够
            MemberBrokerAccountBO memberBrokerAccount = memberBrokerAccountService
                    .queryOneBy(bo.getMemberId(), bo.getBrokerAccountId());
            if (memberBrokerAccount == null || memberBrokerAccount.getAvailableMoney() == null) {
                return ResultUtil.failureResult("账号未配置资金，无法下单！");
            }

            BigDecimal commission = stockOrderService.calcCommission(
                    bo.getMemberId(),
                    bo.getBrokerAccountId(),
                    bo.getPrice().multiply(BigDecimal.valueOf(bo.getVolume())));
            if (memberBrokerAccount.getAvailableMoney()
                    .compareTo(bo.getPrice().multiply(BigDecimal.valueOf(bo.getVolume())).add(commission)) <= 0) {
                return ResultUtil.failureResult("剩余资金不足，无法下单！");
            }

            // 判断是否超过单一股票下单极限
            // (int (总金额 * 30%/20% - 持仓金额, 有效金额) / (买入价格 * 100)) * 100;
            BigDecimal rate = bo.getCode().startsWith("60") || bo.getCode().startsWith("00") ? new BigDecimal("0.3") :
                    (bo.getCode().startsWith("30") ? new BigDecimal("0.2") : new BigDecimal("0"));
            BigDecimal baseMoney = memberBrokerAccount.getBaseMoney();
            if (baseMoney != null && baseMoney.compareTo(new BigDecimal(0)) > 0) {
                BigDecimal availableMoney = memberBrokerAccount.getAvailableMoney();
                BigDecimal positionMoney = new BigDecimal(0);

                StockPositionBO qo = new StockPositionBO();
                qo.setMemberId(bo.getMemberId());
                qo.setBrokerAccountId(bo.getBrokerAccountId());
                qo.setCode(bo.getCode());
                for (StockPositionBO position : stockPositionService.queryList(qo)) {
                    positionMoney = positionMoney.add(position.getPrice().multiply(new BigDecimal(position.getVolume())));
                }

                BigDecimal buyMoney = baseMoney.subtract(positionMoney).multiply(rate);
                if (buyMoney.compareTo(availableMoney) > 0) {
                    buyMoney = availableMoney;
                }

                int buyVolume = buyMoney.divide(bo.getPrice(), 2, RoundingMode.FLOOR)
                        .divide(BigDecimal.valueOf(100), 0, RoundingMode.FLOOR)
                        .multiply(BigDecimal.valueOf(100)).intValue();
                if (buyVolume < bo.getVolume()) {
                    return ResultUtil.failureResult("股票[" + bo.getCode() + "]最多只可" +
                            (positionMoney.compareTo(new BigDecimal(0)) > 0 ? "再" : "") +
                            "买入 " + buyVolume + "股！");
                }
            }
        }

        BrokerAccountBO brokerAccount = brokerAccountService.queryBy(bo.getBrokerAccountId());
        if (brokerAccount == null) return ResultUtil.failureResult("资金账号不存在！");

        StockOrderBO stockOrderBO = getStockOrder(bo);
        stockOrderBO.setAccountId(brokerAccount.getAccount());

        String orderCode = StockUtil.getStockCode(bo.getCode());
        if (StringUtil.isBlank(orderCode)) {
            throw new RuntimeException("证券代码不正确！");
        }

        qmtProxy.order(
                stockOrderBO.getAccountId(),
                orderCode,
                stockOrderBO.getOrderType(),
                stockOrderBO.getVolume(),
                stockOrderBO.getPriceType(),
                stockOrderBO.getPrice().doubleValue(),
                stockOrderBO.getMemberId(),
                stockOrderBO.getId()
        );
        stockOrderService.insert(stockOrderBO);
        return ResultUtil.successResult("已提交报单！");
    }

    private StockOrderBO getStockOrder(OrderBO bo) {
        StockOrderBO stockOrderBO = new StockOrderBO();
        stockOrderBO.setId(Tool.getUUID());
        stockOrderBO.setMemberId(bo.getMemberId());
        stockOrderBO.setBrokerAccountId(bo.getBrokerAccountId());
        stockOrderBO.setOrderType(bo.getOrderType());
        stockOrderBO.setCode(bo.getCode());
        stockOrderBO.setPriceType(Constants.PriceType.FIX_PRICE); // 指定价
        stockOrderBO.setPrice(bo.getPrice());
        stockOrderBO.setVolume(bo.getVolume());
        stockOrderBO.setStatus(StockOrderBO.STATUS_SUBMIT);
        stockOrderBO.setFreezeMoney(new BigDecimal(0));
        stockOrderBO.setFreezeCommission(new BigDecimal(0));
        stockOrderBO.setTradedVolume(0);
        stockOrderBO.setTradedPrice(new BigDecimal(0));
        stockOrderBO.setTradedAmount(new BigDecimal(0));
        stockOrderBO.setCancelVolume(0);
        stockOrderBO.setFinished(0); // 未完成
        stockOrderBO.setUpdateId(bo.getCreateId());
        stockOrderBO.setCreateId(bo.getCreateId());
        return stockOrderBO;
    }

    public Result<?> cancel(OrderBO bo) {
        if (StringUtil.isBlank(bo.getId())) {
            return ResultUtil.failureResult("撤单参数出错！");
        }

        StockOrderBO stockOrderBO = stockOrderService.queryBy(bo.getId());
        if (stockOrderBO == null) {
            return ResultUtil.failureResult("撤单参数不正确！");
        }
        if (!(StockOrderBO.STATUS_REPORTED.equals(stockOrderBO.getStatus())
                || StockOrderBO.STATUS_PART_SUCC.equals(stockOrderBO.getStatus()))) {
            return ResultUtil.failureResult("非委托成功/部撤/部成单不允许撤单！");
        }
        if (StringUtil.isBlank(stockOrderBO.getOrderSysId())) {
            return ResultUtil.failureResult("委托单号不正确！");
        }

        // stockOrderBO.setStatus(StockOrderBO.STATUS_SUBMIT_CANCEL);
        // stockOrderService.save(stockOrderBO);

        BrokerAccountBO accountBO = brokerAccountService.queryBy(stockOrderBO.getBrokerAccountId());
        qmtProxy.cancel(stockOrderBO.getId(), accountBO.getAccount(), stockOrderBO.getOrderSysId());
        return ResultUtil.successResult("已提交撤单！");
    }
}
